// @ts-nocheck
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-empty-function */
import { uuid, getSignature } from './utils'

interface IConnServiceConfig extends Loose {
  origin: string
  app_id: string
  // secret_id: string
  secret_key: string
  vad: number
  hotword_list: string[]
}

export class Credential {
  config: IConnServiceConfig

  constructor(options: IConnServiceConfig) {
    this.config = options
  }

  createQuery() {
    const params: Loose = {}
    const time = new Date().getTime()
    params.origin = this.config.origin
    params.secretid = this.config.secretid
    params.engine_model_type = this.config.engine_model_type || '16k_zh'
    params.timestamp = Math.round(time / 1000)
    params.expired = Math.round(time / 1000) + 24 * 60 * 60
    params.nonce = Math.round(time / 100000)
    params.voice_id = uuid()

    // 非必填参数
    const params_list = [
      'voice_format',
      'hotword_id',
      'needvad',
      'filter_dirty',
      'filter_modal',
      'filter_punc',
      'convert_num_mode',
      'word_info',
      'vad_silence_time'
    ]
    params_list.forEach((key) => {
      if (this.config.hasOwnProperty(key)) {
        params[key] = this.config[key]
      }
    })
    return params
  }

  formatSignString(params) {
    let query_string = ''
    const socket_uri = `${params.origin}/asr/v2/${this.config.appid}`
    const keys = Object.keys(params)
    keys.sort()
    for (let i = 0, len = keys.length; i < len; i++) {
      query_string += `&${keys[i]}=${params[keys[i]]}`
    }
    return `${socket_uri}?${query_string.slice(1)}`
  }

  // 获取签名原文
  getSignStr() {
    const queryObject = this.createQuery()
    return this.formatSignString(queryObject)
  }
}

export default class ConnService {
  // app_id: string
  // secretid: string
  // secret_key: string
  socket: WebSocket | null
  signSucceed: boolean
  recCompleted: boolean
  socketConsume: number
  exceedRecord: string[] = []
  config: IConnServiceConfig
  getSignature: (...params: any[]) => any = getSignature

  constructor(config: IConnServiceConfig) {
    this.config = config || {}
    this.socket = null
    this.signSucceed = false
    this.recCompleted = false
    this.socketConsume = 0
    if (config.getSignature) {
      this.getSignature = config.getSignature
    }
  }

  async getUrl() {
    if (!this.config.app_id || !this.config.secret_key) {
      return Promise.reject({ code: 10401, message: 'app_id或secret_key缺失' })
    }
    const query = new URLSearchParams()
    const timestamp = String(Math.floor(Date.now() / 1000))
    query.set('timestamp', timestamp)
    query.set('app_id', this.config.app_id)
    query.set('session_id', uuid())
    if (this.config.vad) {
      query.set('vad', String(this.config.vad))
    }
    query.sort()
    const signSring = query.toString()
    const signature = this.getSignature(this.config.secret_key, signSring)
    query.set('signature', signature)
    return `${this.config.origin}?${query.toString()}`
    // const auth = new Credential(this.config)
    // const sign_str = auth.getSignStr()
    // let removed = sign_str.replace(/ws:\/\//, '')
    // removed = removed.replace(/wss:\/\//, '')
    // return `${sign_str}&signature=${encodeURIComponent(this.getSignature(this.secret_key, removed))}`
  }

  /**
   * @description 完成鉴权
   * @returns
   */
  async setup(): Promise<SdkError> {
    const url = await this.getUrl()
    const UserWebSocket = window.WebSocket || (window.MozWebSocket as WebSocket)
    if (!UserWebSocket) {
      this.onError({ code: 10400, message: '浏览器不支持WebSocket' })
      return
    }
    this.socket = new UserWebSocket(url)
    const now = Date.now()
    console.time('socket_auth_consume')
    this.socket.onopen = (ev) => {
      this.socketConsume = Date.now() - now
      this.recCompleted = false
      this.onSocketOpen(ev)
      setTimeout(() => {
        this.sendStart()
      })
    }
    this.socket.onmessage = (e) => {
      const response: IScoketRes = JSON.parse(e.data)
      if (response.error_code !== 0) {
        this.onError({ code: 10501, message: response.error_reason })
        this.socket.close()
        return
      }
      if (!this.signSucceed) {
        console.timeEnd('socket_auth_consume')
        // 服务端返回第一条code为0的信息表鉴权成功
        this.onRecStart(response)
        this.signSucceed = true
      }
      if (response.data) {
        if (response.error_reason === 'end') {
          this.onRecComplete(response)
          this.recCompleted = true
          return
        }
        const { type, vad_state } = response.data
        if (type == 'partial_result') {
          this.checkShouldPrepend(response.data)
          this.onSentenceChange(response.data)
        }
        if (type == 'final_result') {
          if (vad_state === 3) {
            console.log('vad_state:', 3)
            response.data.type = 'partial_result'
            this.checkShouldPrepend(response.data)
            this.onSentenceChange(response.data)
            this.exceedRecord.push(response.data.sentence)
          } else {
            this.checkShouldPrepend(response.data)
            this.onSentenceEnd(response.data)
            this.exceedRecord = []
          }
        }
      }
    }
    this.socket.onerror = (e: Event) => {
      console.warn('长连接异常', e)
      this.socket?.close()
    }
    this.socket.onclose = () => {
      console.warn('长连接已关闭')
      this.exceedRecord = []
    }
  }

  checkShouldPrepend(data) {
    if (this.exceedRecord.length) {
      data.sentence = this.exceedRecord.join('') + data.sentence
    }
  }

  sendStart() {
    if (!this.socket || this.socket.readyState !== 1) {
      this.onError({ code: 10401, message: '连接未建立，请稍后发送数据！' })
      return
    }
    this.socket.send(
      JSON.stringify({
        signal: 'start',
        hotword_list: this.config.hotword_list
      })
    )
  }

  /**
   * @description 发送数据
   * @param {ArrayBuffer}
   * @returns
   */
  sendBuffer(data) {
    if (!this.socket || this.socket.readyState !== 1) {
      this.onError({ code: 10401, message: '连接未建立，请稍后发送数据！' })
      return
    }
    this.socket.send(data)
  }

  sendEndMsg() {
    if (this.socket && this.socket.readyState === 1) {
      this.socket.send(JSON.stringify({ signal: 'end' }))
    } else {
      console.warn('链接已关闭')
    }
  }

  start() {
    this.setup()
  }

  // 暂停识别，关闭连接
  stop() {
    return new Promise((resolve, reject) => {
      try {
        if (this.socket?.readyState === 1) {
          this.socket.send(JSON.stringify({ signal: 'end' }))
        }
        this.socket?.close()
        resolve()
      } catch {
        reject()
      }
    })
  }

  /**
   * @description 建立连接的时候
   * @param {*} res
   */
  onSocketOpen(res) { }

  /**
   * @description 开始识别的时候
   * @param {*} res
   */
  onRecStart(res) { }

  /**
   * @description 识别结果发生变化的时候
   * @param {*} res
   */
  onSentenceChange(res) { }

  /**
   * @description 一句话结束的时候
   * @param {*} res
   */
  onSentenceEnd(res) { }

  /**
   * @description 识别结束的时候
   * @param {*} res
   */
  onRecComplete(res) { }

  /**
   * @description 识别失败
   * @param {string}
   */
  onError(res) { }
}
